﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ChanSharp
{
    public static class Extensions
    {
        static char[] splitChars = new char[] { ' ', '-', '\t','\n' };

        //public static string WordWraps(this string str, int width)
        //{
        //    string[] words = str.Explode(splitChars);

        //    int curLineLength = 0;
        //    StringBuilder strBuilder = new StringBuilder();
        //    for (int i = 0; i < words.Length; i += 1)
        //    {
        //        string word = words[i];
        //        // If adding the new word to the current line would be too long,
        //        // then put it on a new line (and split it up if it's too long).
        //        if (curLineLength + word.Length > width)
        //        {
        //            // Only move down to a new line if we have text on the current line.
        //            // Avoids situation where wrapped whitespace causes emptylines in text.
        //            if (curLineLength > 0)
        //            {
        //                strBuilder.Append(Environment.NewLine);
        //                curLineLength = 0;
        //            }

        //            // If the current word is too long to fit on a line even on it's own then
        //            // split the word up.
        //            while (word.Length > width)
        //            {
        //                strBuilder.Append(word.Substring(0, width - 1) + "-");
        //                word = word.Substring(width - 1);

        //                strBuilder.Append(Environment.NewLine);
        //            }

        //            // Remove leading whitespace from the word so the new line starts flush to the left.
        //            word = word.TrimStart();
        //        }
        //        strBuilder.Append(word);
        //        curLineLength += word.Length;
        //    }

        //    return strBuilder.ToString();
        //}

        public static string[] Explode(this string str, char[] splitChars)
        {
            List<string> parts = new List<string>();
            int startIndex = 0;
            while (true)
            {
                int index = str.IndexOfAny(splitChars, startIndex);

                if (index == -1)
                {
                    parts.Add(str.Substring(startIndex));
                    return parts.ToArray();
                }

                string word = str.Substring(startIndex, index - startIndex);
                char nextChar = str.Substring(index, 1)[0];
                // Dashes and the likes should stick to the word occuring before it. Whitespace doesn't have to.
                if (char.IsWhiteSpace(nextChar))
                {
                    parts.Add(word);
                    parts.Add(nextChar.ToString());
                }
                else
                {
                    parts.Add(word + nextChar);
                }

                startIndex = index + 1;
            }
        }

        private const string _newline = "\n";

        /// <summary>
        /// Word wraps the given text to fit within the specified width.
        /// </summary>
        /// <param name="text">Text to be word wrapped</param>
        /// <param name="width">Width, in characters, to which the text
        /// should be word wrapped</param>
        /// <returns>The modified text</returns>
        public static string WordWrap(this string text, int width)
        {
            int pos, next;
            StringBuilder sb = new StringBuilder();

            // Lucidity check
            if (width < 1)
                return text;

            // Parse each line of text
            for (pos = 0; pos < text.Length; pos = next)
            {
                // Find end of line
                int eol = text.IndexOf(_newline, pos);
                if (eol == -1)
                    next = eol = text.Length;
                else
                    next = eol + _newline.Length;

                // Copy this line of text, breaking into smaller lines as needed
                if (eol > pos)
                {
                    do
                    {
                        int len = eol - pos;
                        if (len > width)
                            len = BreakLine(text, pos, width);

                        sb.Append(text, pos, len);
                        sb.Append(_newline);
                        // Trim whitespace following break
                        pos += len;
                        while (pos < eol && Char.IsWhiteSpace(text[pos]))
                            pos++;
                    } while (eol > pos);
                }
                else sb.Append(_newline); // Empty line
            }
            return sb.ToString();
        }

        /// <summary>
        /// Locates position to break the given line so as to avoid
        /// breaking words.
        /// </summary>
        /// <param name="text">String that contains line of text</param>
        /// <param name="pos">Index where line of text starts</param>
        /// <param name="max">Maximum line length</param>
        /// <returns>The modified line length</returns>
        public static int BreakLine(string text, int pos, int max)
        {
            // Find last whitespace in line
            int i = max - 1;
            while (i >= 0 && !Char.IsWhiteSpace(text[pos + i]))
                i--;
            if (i < 0)
                return max; // No whitespace found; break at maximum length

            // Find start of whitespace
            while (i >= 0 && Char.IsWhiteSpace(text[pos + i]))
                i--;

            // Return length of text before whitespace
            return i + 1;
        }
    }
}
